package com.vnie.mina.message;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;

import com.vnie.mina.util.Util;

/**
 * 发送报文，各个域中存放的是tlv格式的数据，接受报文为解包后的报文，也就是tlv 中的v
 * @author rainman
 *
 */
public class BaseMessage {

	/** 1.报文长度=报文头长度+报文体长度+MAC长度 */
	private byte[] len;

	/** 2.报文头* */
	// TPDU 银商增值应用统一为: 6000130000
	private byte[] tpdu;
	// 应用代码 生产环境3000，测试环境4000 以0x00结尾
	private byte[] appcode;
	/** 3.报文体 TLV(TAG+LENGTH+VALUE) **/
	private byte[] retcode;// 0返回码 　
	private byte[] retmsg;// 1返回信息 　
	private byte[] version;// 2版本号 　
	private byte[] trcode;// 3交易代码 　
	private byte[] exmchtid;// 4外部商户代码 　
	private byte[] extermid;// 5外部终端号 　
	private byte[] payway;//6支付方式(0-现金,1-pos，2-cp)
	private byte[] bankcard;//7银行卡号,压缩不足位时后补f 
	private byte[] track2;//8二磁,压缩不足位时右补f
	private byte[] track3;//9三磁,压缩不足位时右补f
	private byte[] amt;//10交易金额,压缩时左补0
	private byte[] pin;//11 16字节pin(或压缩成8字节)
	private byte[] vender;//12 服务商代码
	private byte[] ttype;//13 业务类型
	private byte[] custid;//14 客户号
	private byte[] serial;//15 终端流水
	private byte[] trser;//16 合作方业务流水
	private byte[] mchtid;//17 中心商户代码
	private byte[] termid;//18 中心终端号
	private byte[] balance;//19 可能带正负号的余额，如:100.01 -99.99
	private byte[] pbatch;//20 中心批次号
	private byte[] pserial;//21 中心终端流水
	private byte[] authno;//22 授权号
	private byte[] cser;//23 中心流水
	private byte[] settdate;//24 清算日期(yyyymmdd)
	private byte[] expire;//25 有效期(yymm)
	private byte[] inscode;//26 发卡行
 	private byte[] acqcode;//27 收单行
	private byte[] tser;//28 第三方业务受理流水
	private byte[] pinfo;//29 小票信息(0-无小票,>0打印n联)
	private byte[] tprt;//30 终端打印类型(0-无打印机,1-热敏,2-针打, 3-套打)
	private byte[] f1;//56 附加字段(可视字符域)
	private byte[] f1b;//57 附加字段(二进制字符域)
	private byte[] f2;//58 附加字段(可视字符域),如小票信息
	private byte[] f2b;//59 附加字段(二进制字符域)
	private Map<String, String> propTable = new HashMap<String,String>();
	//计算后的mac
	private byte[] mac;
	
	// 组装后的报文实体
	protected byte[] entity;
	
	public BaseMessage(){
		//初始化报文tag,字段对应关系表
		propTable.put("0", "retcode");
		propTable.put("1", "retmsg");
		propTable.put("2", "version");
		propTable.put("3", "trcode");
		propTable.put("4", "exmchtid");
		propTable.put("5", "extermid");
		propTable.put("6", "payway");
		propTable.put("7", "bankcard");
		propTable.put("8", "track2");
		propTable.put("9", "track3");
		propTable.put("10", "amt");
		propTable.put("11", "pin");
		propTable.put("12", "vender");
		propTable.put("13", "ttype");
		propTable.put("14", "custid");
		propTable.put("15", "serial");
		propTable.put("16", "trser");
		propTable.put("17", "mchtid");
		propTable.put("18", "termid");
		propTable.put("19", "balance");
		propTable.put("20", "pbatch");
		propTable.put("21", "pserial");
		propTable.put("22", "authno");
		propTable.put("23", "cser");
		propTable.put("24", "settdate");
		propTable.put("25", "expire");
		propTable.put("26", "inscode");
		propTable.put("27", "acqcode");
		propTable.put("28", "tser");
		propTable.put("29", "pinfo");
		propTable.put("30", "tprt");
		propTable.put("56", "f1");
		propTable.put("57", "f1b");
		propTable.put("58", "f2");
		propTable.put("59", "f2b");
		
		//公用字段赋值
		try {
			setTpdu(Util.str2Bcd(VConstant.TPDU));
			setAppcode(VConstant.APPCODE_TEST.getBytes(VConstant.ASCII));
			setVersion(Util.buildTLV(2, VConstant.VERSION));
			setExmchtid(Util.buildTLV(4, VConstant.EXMCHTID));
			setExtermid(Util.buildTLV(5, VConstant.EXTERMID));
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public byte[] getMac() {
		return mac;
	}

	public void setMac(byte[] mac) {
		this.mac = mac;
	}

	public byte[] getLen() {
		return len;
	}

	public void setLen(byte[] len) {
		this.len = len;
	}

	public byte[] getTpdu() {
		return tpdu;
	}

	public void setTpdu(byte[] tpdu) {
		this.tpdu = tpdu;
	}

	public byte[] getAppcode() {
		return appcode;
	}

	public void setAppcode(byte[] appcode) {
		this.appcode = appcode;
	}

	public byte[] getRetcode() {
		return retcode;
	}

	public void setRetcode(byte[] retcode) {
		this.retcode = retcode;
	}

	public byte[] getRetmsg() {
		return retmsg;
	}

	public void setRetmsg(byte[] retmsg) {
		this.retmsg = retmsg;
	}

	public byte[] getVersion() {
		return version;
	}

	public void setVersion(byte[] version) {
		this.version = version;
	}

	public byte[] getTrcode() {
		return trcode;
	}

	public void setTrcode(byte[] trcode) {
		this.trcode = trcode;
	}

	public byte[] getExmchtid() {
		return exmchtid;
	}

	public void setExmchtid(byte[] exmchtid) {
		this.exmchtid = exmchtid;
	}

	public byte[] getExtermid() {
		return extermid;
	}

	public void setExtermid(byte[] extermid) {
		this.extermid = extermid;
	}

	public byte[] getSerial() {
		return serial;
	}

	public void setSerial(byte[] serial) {
		this.serial = serial;
	}

	public byte[] getF1b() {
		return f1b;
	}

	public void setF1b(byte[] f1b) {
		this.f1b = f1b;
	}
	
	public byte[] getEntity() {
        return entity;
    }

    public void setEntity(byte[] entity) {
        this.entity = entity;
    }
    
    public byte[] getPayway() {
		return payway;
	}

	public void setPayway(byte[] payway) {
		this.payway = payway;
	}

	public byte[] getBankcard() {
		return bankcard;
	}

	public void setBankcard(byte[] bankcard) {
		this.bankcard = bankcard;
	}

	public byte[] getTrack2() {
		return track2;
	}

	public void setTrack2(byte[] track2) {
		this.track2 = track2;
	}

	public byte[] getTrack3() {
		return track3;
	}

	public void setTrack3(byte[] track3) {
		this.track3 = track3;
	}

	public byte[] getAmt() {
		return amt;
	}

	public void setAmt(byte[] amt) {
		this.amt = amt;
	}

	public byte[] getPin() {
		return pin;
	}

	public void setPin(byte[] pin) {
		this.pin = pin;
	}

	public byte[] getVender() {
		return vender;
	}

	public void setVender(byte[] vender) {
		this.vender = vender;
	}

	public byte[] getTtype() {
		return ttype;
	}

	public void setTtype(byte[] ttype) {
		this.ttype = ttype;
	}

	public byte[] getCustid() {
		return custid;
	}

	public void setCustid(byte[] custid) {
		this.custid = custid;
	}

	public byte[] getTrser() {
		return trser;
	}

	public void setTrser(byte[] trser) {
		this.trser = trser;
	}

	public byte[] getMchtid() {
		return mchtid;
	}

	public void setMchtid(byte[] mchtid) {
		this.mchtid = mchtid;
	}

	public byte[] getTermid() {
		return termid;
	}

	public void setTermid(byte[] termid) {
		this.termid = termid;
	}

	public byte[] getBalance() {
		return balance;
	}

	public void setBalance(byte[] balance) {
		this.balance = balance;
	}

	public byte[] getPbatch() {
		return pbatch;
	}

	public void setPbatch(byte[] pbatch) {
		this.pbatch = pbatch;
	}

	public byte[] getPserial() {
		return pserial;
	}

	public void setPserial(byte[] pserial) {
		this.pserial = pserial;
	}

	public byte[] getAuthno() {
		return authno;
	}

	public void setAuthno(byte[] authno) {
		this.authno = authno;
	}

	public byte[] getCser() {
		return cser;
	}

	public void setCser(byte[] cser) {
		this.cser = cser;
	}

	public byte[] getSettdate() {
		return settdate;
	}

	public void setSettdate(byte[] settdate) {
		this.settdate = settdate;
	}

	public byte[] getExpire() {
		return expire;
	}

	public void setExpire(byte[] expire) {
		this.expire = expire;
	}

	public byte[] getInscode() {
		return inscode;
	}

	public void setInscode(byte[] inscode) {
		this.inscode = inscode;
	}

	public byte[] getAcqcode() {
		return acqcode;
	}

	public void setAcqcode(byte[] acqcode) {
		this.acqcode = acqcode;
	}

	public byte[] getTser() {
		return tser;
	}

	public void setTser(byte[] tser) {
		this.tser = tser;
	}

	public byte[] getPinfo() {
		return pinfo;
	}

	public void setPinfo(byte[] pinfo) {
		this.pinfo = pinfo;
	}

	public byte[] getTprt() {
		return tprt;
	}

	public void setTprt(byte[] tprt) {
		this.tprt = tprt;
	}

	public byte[] getF1() {
		return f1;
	}

	public void setF1(byte[] f1) {
		this.f1 = f1;
	}

	public byte[] getF2() {
		return f2;
	}

	public void setF2(byte[] f2) {
		this.f2 = f2;
	}

	public byte[] getF2b() {
		return f2b;
	}

	public void setF2b(byte[] f2b) {
		this.f2b = f2b;
	}
	
	

	public Map<String, String> getPropTable() {
		return propTable;
	}

	public void setPropTable(Map<String, String> propTable) {
		this.propTable = propTable;
	}

	/**
	 * request复写此方法拼装报文
	 */
	public void encode(){
	};
	
	/**
	 * response复写此方法解包
	 */
	public void decode(){
		byte[] entityBody = new byte[entity.length-VConstant.LEN_HEAD-VConstant.LEN_LENGTH-VConstant.LEN_MAC];
		System.arraycopy(entity, VConstant.LEN_HEAD+VConstant.LEN_LENGTH, entityBody, 0, entityBody.length);
		while(entityBody.length>0) {
			Map<String,Object> TLVMap = Util.unpackTLV(entityBody);
			String tag = String.valueOf((Integer)TLVMap.get("tag"));
			byte[] value = (byte[])TLVMap.get("value");
			entityBody = (byte[])TLVMap.get("entity");
			try {
				PropertyUtils.setProperty(this, propTable.get(tag),value);
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}
